/*
* FILENAME:		stack_seq.c/stack_seq.h 
* CREATED AT:		2012/May/28
* DECRITION:		the module stack, include sequence implement and list implement
* 
* MODULE:		linead list
* PLATFORM:		ubuntu-12.04/gcc-4.6.3
* AUTHOR:		incarnation-lee
* 
* ----------------------REVISION HISTROY------------------------
* No.	Date	Revised by	Function	Descrition
* 1	12/5/28	incar-lee	stack_seq_demo	created the stack list demo function
* 2	12/5/28 incar-lee	init_sqk	created and defines
  3	12/5/30	incar-lee	destory		created and defines
  4	12/5/31	incar-lee	clear,length,	implement basic defines
				top,empty,
				pop,push
  5	12/6/5	incar-lee	pop		fix a bug of forget update rest field
  6	12/6/10	incar-lee	pop		if pop element has no sense
  7	12/6/10	incar-lee	isContain	if a element in stack
*
*/

/* Standard C */
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <assert.h>
#include <errno.h>

/* linux related */
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>

/* user defined */
#include "externals.h"
#include "udgtd.h"
#include "stack_seq.h"
#include "errcode.h"


STATUS stack_seq_demo()
{
	STATUS result = 0;
	S_sqstack sqstack_demo;
	S_element *top;
	S_element out_ele;
	S_element ele_1 = {65,1,'A',};
	S_element ele_2 = {66,2,'B',};
	S_element ele_3 = {67,3,'C',};
	S_element ele_4 = {68,4,'D',};
	
	sqstack_demo.base = NULL;		/* for init sqstack_demo */	
	sqstack_demo.top = NULL;

	/* initiliazie a sequence stack */
	result = init_sqk(&sqstack_demo);
	if(__builtin_expect(!!result,0))
		return -1;

	/* stack exits by first */
	result = isEmpty_sqk(&sqstack_demo);
	if(__builtin_expect(!!result,0))
		return -1;
	
	/* push and pop element */
	push_sqk(&sqstack_demo,&ele_1);
	push_sqk(&sqstack_demo,&ele_2);
	push_sqk(&sqstack_demo,&ele_3);
	push_sqk(&sqstack_demo,&ele_4);
	pop_sqk(&sqstack_demo,&out_ele);
	push_sqk(&sqstack_demo,&ele_1);
	pop_sqk(&sqstack_demo,&out_ele);
	pop_sqk(&sqstack_demo,&out_ele);
	push_sqk(&sqstack_demo,&ele_4);

	/* stack exits return length */
	result = length_sqk(&sqstack_demo);

	top = top_sqk(&sqstack_demo);
	if(__builtin_expect(!!(NULL==top),0))
		return -1;

	/* stack exits */
	result = clear_sqk(&sqstack_demo);
	if(__builtin_expect(!!result,0))
		return -1;

	/* stack exits by first */
	result = destory_sqk(&sqstack_demo);
	if(__builtin_expect(!!result,0))
		return -1;
	return 0;
}



/*********************************
** opterations on sequence stack *
**********************************/

/* 
* initiliazie a sequence stack 
*/
 STATUS init_sqk(S_sqstack *sqk_demo)
{
	assert(NULL!=sqk_demo);
	
	gmalloc((void**)&sqk_demo->base,STACK_SEQ_SIZE*sizeof(S_element));	
	if(__builtin_expect(!!(NULL==sqk_demo->base),0))
	{
		set_errcode(MEMORYNA);
		return -1;
	}
	sqk_demo->top = sqk_demo->base;
	sqk_demo->rest = STACK_SEQ_SIZE;
	memset(sqk_demo->base,0,sizeof(S_element)*STACK_SEQ_SIZE);
	return 0;
}


/* 
* stack exits by first, take care of destory without clear
*/
 STATUS destory_sqk(S_sqstack *sqk_demo)
{
	assert(NULL!=sqk_demo);

	if(NULL!=sqk_demo->base)
	{
		free(sqk_demo->base);
		sqk_demo->base = NULL;
		sqk_demo->top = NULL;
		sqk_demo->rest = 0;
		return 0;
	}
	set_errcode(NoEXIT);
	return -1;
}

/*
* stack exits 
*/
 STATUS clear_sqk(S_sqstack *sqk_demo)
{
	assert(NULL!=sqk_demo);

	if(NULL!=sqk_demo->base)
	{
		sqk_demo->top = sqk_demo->base;
		sqk_demo->rest = STACK_SEQ_SIZE;
		memset(sqk_demo->base,0,STACK_SEQ_SIZE*sizeof(S_element));
		return 0;
	}
	set_errcode(NoEXIT);
	return -1;	
}

/* 
* if stack exit and empty 
*/
 STATUS isEmpty_sqk(S_sqstack *sqk_demo)
{
	assert(NULL!=sqk_demo);	

	if(NULL==sqk_demo->base)
	{
		set_errcode(NoEXIT);
		return -1;
	}
	if(sqk_demo->base==sqk_demo->top) 			/* somewhat record rest error */
	{
		if(sqk_demo->rest == STACK_SEQ_SIZE)
			return 0;
		set_errcode(INCONSISTENT);
		return -1;
	}
	return 1;
}

/* 
* stack exits return length 
*/
 size_t length_sqk(S_sqstack *sqk_demo)
{
	size_t len = 0;
	assert(NULL!=sqk_demo);

	if(NULL==sqk_demo->base)
	{
		set_errcode(NoEXIT);
		return -1;	
	}

	len = ((int)sqk_demo->top - (int)sqk_demo->base)/sizeof(S_element);
	return len;
}

/* 
* stack exits return top elements 
*/
 S_element *top_sqk(S_sqstack *sqk_demo)
{
	assert(NULL!=sqk_demo);

	if(NULL==sqk_demo->base)
	{
		set_errcode(NoEXIT);
		return NULL;
	}
	return sqk_demo->top-1;
}

/* 
* push a elemen on the exited stack 
*/
 STATUS push_sqk(S_sqstack *sqk_demo,S_element *ele)
{
	assert(NULL!=sqk_demo);

	if(NULL==sqk_demo->base)
	{
		set_errcode(NoEXIT);
		return -1;	
	}
	if(0==sqk_demo->rest)
	{
		set_errcode(NMSPACE);
		return -1;
	}
	memcpy(sqk_demo->top++,ele,sizeof(S_element));			/* keep memory sequence */
	sqk_demo->rest--;
	return 0;
}

/*
* pop a elemen on the exited stack 
*/
 STATUS pop_sqk(S_sqstack *sqk_demo,S_element *output)
{
	assert(NULL!=sqk_demo);

	if(NULL==sqk_demo->base)
	{
		set_errcode(NoEXIT);
		return -1;	
	}
	if(sqk_demo->base==sqk_demo->top)
	{
		set_errcode(NoEXIT);
		return -1;
	}

	sqk_demo->top--;
	if(NULL!=output)						/* sometimes we just pop */
		memcpy(output,sqk_demo->top,sizeof(S_element));	/* cpy data */
	memset(sqk_demo->top,0,sizeof(S_element));
	sqk_demo->rest++;
	return 0;
}


/* 
* if contain the same element, contain return 0,or return 1 
*/
STATUS isContain_sqk(S_sqstack *sqk_demo,S_element *ele)
{
	int i = 0;
	S_element *tmp;
	assert(NULL!=sqk_demo);
	assert(NULL!=ele);

	tmp = sqk_demo->base;	
	for(i=0;i<length_sqk(sqk_demo);i++)
	{
		if(0==memcmp(tmp++,ele,sizeof(S_element)))
			return 0;
	}
	return 1;	
}
